ModelSerializer 序列化组件
只要继承了 APIView 就可以使用 ModelSerializer
ModelSerializer 的使用和 ModelForm 组件的使用类似
1.ModelSerializer的基本使用
# serializer.py
from rest_framework import serializers
from .models import *
class BookSerializers(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
# 自定义错误信息
extra_kwargs = {
"title": {
'error_messages': {
'required': '书籍名称不能为空'
}
},
'price': {
'error_messages': {
'required': '价格不能为空'
}
},
'pub_date': {
'error_messages': {
'required': '日期不能为空'
}
},
'publish': {
'error_messages': {
'required': '出版社不能为空'
}
},
'author': {
'error_messages': {
'required': '作者不能为空'
}
}
}
# views.py
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import *
from .serializer import *
class BookView(APIView):
# 查看所有书籍
def get(self, request):
book_list = Book.objects.all()
bs = BookSerializers(book_list, many=True)
return Response(bs.data)
# 添加书籍
def post(self, request):
bs = BookSerializers(data=request.data)
if bs.is_valid(): # 验证数据是否有误
print(bs.validated_data) # 验证过后正确的数据: OrderedDict([('title', '三国演义'), ('price', 100), ('pub_date', datetime.date(2012, 12, 12)), ('publish', <Publish: 东莞出版社>), ('authors', [<Author: Kevin>, <Author: Aimer>])])
bs.save() # 保存数据,实际上调用的是 rest-framework 中的 create 方法
return Response(bs.data)
else:
return Response(bs.errors) # bs.errors 验证过后的错误信息
class BookDetailView(APIView):
# 查看指定的书籍
def get(self, request, id):
book_obj = Book.objects.filter(pk=id).first()
if book_obj:
bs = BookSerializers(book_obj)
return Response(bs.data)
else:
return Response({'static': 0, 'message': '没有该书籍'})
# 修改书籍
def put(self, request, id):
book_obj = Book.objects.filter(pk=id).first()
bs = BookSerializers(book_obj, data=request.data) # 修改数据的时候一定要指定修改那条数据(即: book_obj),否则在执行 .save() 的时候就相当于新增数据
if bs.is_valid(): # 验证数据是否有误
bs.save() # 保存数据,实际上调用的是 rest-framework 中的 update 方法
return Response(bs.data)
else:
return Response(bs.errors) # bs.errors 验证过后的错误信息
# 删除书籍
def delete(self, request, id):
Book.objects.filter(pk=id).delete()
return Response()
# urls.py
urlpatterns = [
……
url(r'book/$', BookView.as_view()),
url(r'book/(\d+)', BookDetailView.as_view())
]
# 接口说明: 查看所有书籍
# 接口: http://127.0.0.1:8000/book/
# 请求类型: GET
# 结果:
[
{
"id": 2,
"title": "三体",
"price": 222,
"pub_date": null,
"publish": 1,
"authors": [
2
]
},
{
"id": 5,
"title": "三国演义",
"price": 100,
"pub_date": "2012-12-12",
"publish": 1,
"authors": [
1,
2
]
}
]
# --------------------------------------------------------------
# 接口说明: 添加书籍
# 接口: http://127.0.0.1:8000/book/
# 请求类型: POST
# 发送数据的编码格式: application/json -> 即: json 格式
# 所要发送的数据: {"title":"勿忘我","price":100,"pub_date":"2012-12-12","publish":1,"authors":[1,2]}
# 结果:
{
"id": 14,
"title": "勿忘我",
"price": 100,
"pub_date": "2012-12-12",
"publish": 1,
"authors": [
1,
2
]
}
# --------------------------------------------------------------
# 接口说明: 查看指定书籍
# 接口: http://127.0.0.1:8000/book/2
# 请求类型: GET
# 结果:
{
"id": 2,
"title": "三体",
"price": 222,
"pub_date": null,
"publish": 1,
"authors": [
2
]
}
# --------------------------------------------------------------
# 接口说明: 修改书籍
# 接口: http://127.0.0.1:8000/book/2
# 请求类型: PUT
# 发送数据的编码格式: application/json -> 即: json 格式
# 所要发送的数据: {"title":"三体(第二部)","price":100,"pub_date":"2012-12-12","publish":1,"authors":[1,2]}
# 结果:
{
"id": 2,
"title": "三体(第二部)",
"price": 100,
"pub_date": "2012-12-12",
"publish": 1,
"authors": [
2,
1
]
}
# --------------------------------------------------------------
# 接口说明: 删除书籍
# 接口: http://127.0.0.1:8000/book/11
# 请求类型: DELETE
# 结果:
空
2.save() 方法的说明
- 执行 save() 之前一定要执行 is_valid() 方法,否则会报错
- .save() 方法的返回值就是所添加/修改的该条数据对象
# views.py
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import *
from .serializer import *
class BookView(APIView):
# 添加书籍
def post(self, request):
bs = BookSerializers(data=request.data)
if bs.is_valid(): # 验证数据是否有误
data_obj = bs.save()
print(data_obj.title, data_obj.price) # 三体 100
return Response(bs.data)
else:
return Response(bs.errors)
3.自定制字段
- 当 fields = '__all__' 的时候,但是又想对里面的某些字段进行单独配置的时候,可以直接在 ModelSerializer 类中重新编写该字段,那么该字段的配置就会覆盖掉之前的配置
- 建议: 如果使用了 ModelSerializer 就尽量不要自定制字段,否则容易出现问题
- 注意:
- 当自定制一对多字段的时候,并且使用了source参数,那么就需要重写save()方法中的create()和update()方法
- 当自定制多对多字段的时候,添加或修改数据多对多字段的数据会有问题
# serializer.py
class BookSerializers(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
extra_kwargs = {
"title": {
'error_messages': {
'required': '书籍名称不能为空'
}
},
'price': {
'error_messages': {
'required': '价格不能为空'
}
},
'pub_date': {
'error_messages': {
'required': '日期不能为空'
}
},
'publish': {
'error_messages': {
'required': '出版社不能为空'
}
},
'author': {
'error_messages': {
'required': '作者不能为空'
}
}
}
publish = serializers.CharField(source="publish.name") # 重新编写 publish 字段的配置
4. 重写 save() 中的 create() 和 update() 方法
- .save()方法实际上调用的是 rest-framework 中的 create 或者 update 方法
- 重写create()/update()方法就是自己将提交过来的数据保存到数据库,并且返回当前保存的数据
- 什么时候需要重写
- 当使用了自定制字段,并且在字段方法中传递了source参数 -> 通俗理解: 当自定制一对多字段的时候,并且使用了source参数,那么就需要重写save()方法中的create()和update()方法
# serializer.py
class BookSerializers(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
extra_kwargs = {
"title": {
'error_messages': {
'required': '书籍名称不能为空'
}
},
'price': {
'error_messages': {
'required': '价格不能为空'
}
},
'pub_date': {
'error_messages': {
'required': '日期不能为空'
}
},
'publish': {
'error_messages': {
'required': '出版社不能为空'
}
},
'author': {
'error_messages': {
'required': '作者不能为空'
}
}
}
publish = serializers.CharField(source="publish.pk") # 重新编写 publish 字段的配置
# 重写 save() 中的 create() 方法
def create(self, validated_data):
"""
:param validated_data: 通过验证的数据
"""
print(validated_data)
book = Book.objects.create(title=validated_data['title'], price=validated_data['price'], pub_date=validated_data['pub_date'], publish_id=validated_data['publish']['pk'])
book.authors.add(*validated_data["authors"])
return book
# 重写 save() 中的 update() 方法
def update(self, instance, validated_data):
"""
:param instance: 需要修改的查询到的数据对象
:param validated_data: 通过验证的数据
"""
for key, val in validated_data.items():
if hasattr(instance, key):
if 'publish' == key:
instance.publish_id = validated_data['publish']['pk']
elif 'authors' == key:
instance.authors.set(validated_data['authors'])
else:
setattr(instance, key, val)
instance.save()
return instance
超链接API: Hyperlinked
1.HyperlinkedIdentityField 字段方法
- HyperlinkedIdentityField 字段方法一般都是用在一对多字段上
- HyperlinkedIdentityField 字段方法返回的是一个url路径
- HyperlinkedIdentityField 字段方法一般在前后端分离的时候很少会使用
- 使用场景: 分页器
- 注意: 如果你所定义的 序列化类 使用了 HyperlinkedIdentityField 字段方法,那么在实例化 序列化类 的时候一定要设置 context={'request': request},否则会报错
# urls.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'publish/(?P<pk>\d+)', PublishDetailView.as_view(), name='publish_detail'),
url(r'book/$', BookView.as_view())
]
# serializer.py
from rest_framework import serializers
from .models import *
class PublishSerializers(serializers.Serializer):
name = serializers.CharField()
email = serializers.CharField()
class BookSerializers(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
# view_name -> url别名
# lookup_field -> 当前外键字段(一对多)在数据库中的字段名
# lookup_url_kwarg -> 分组命名匹配中的别名
publish = serializers.HyperlinkedIdentityField(view_name='publish_detail', lookup_field='publish_id', lookup_url_kwarg='pk')
# views.py
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import *
from .serializer import *
class BookView(APIView):
# 查看所有书籍
def get(self, request):
book_list = Book.objects.all()
bs = BookSerializers(book_list, many=True, context={'request': request}) # 如果你所定义的 序列化类 使用了 HyperlinkedIdentityField 字段方法,那么在实例化 序列化类 的时候一定要设置 context={'request': request},否则会报错
return Response(bs.data)
class PublishDetailView(APIView):
# 查看指定的出版社
def get(self, request, pk):
publish_obj = Publish.objects.filter(pk=pk).first()
if publish_obj:
ps = PublishSerializers(publish_obj)
return Response(ps.data)
else:
return Response({'static': 0, 'message': '没有该出版社'})
# 接口: http://127.0.0.1:8000/book/
# 请求类型: GET
# 结果:
[
{
"id": 2,
"publish": "http://127.0.0.1:8000/publish/1",
"title": "三体",
"price": 222,
"pub_date": null,
"authors": [
2
]
},
……
]